package cn.touna.jss.modules.custom.carmodel.synctask;

import cn.touna.jss.modules.credit.entity.TaskRecordEntity;
import cn.touna.jss.modules.credit.mapper.TaskRecordEntityMapper;
import cn.touna.jss.modules.custom.carmodel.dto.TaskInfo;
import cn.touna.risk.threadpool.common.util.ThreadPoolUtil;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooKeeper;
import org.apache.zookeeper.data.Stat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by Steve.Tao on 2017/11/17.
 */
@Component
public class DateDistributeTaskId {

    private static final Logger logger = LogManager.getLogger();

    @Autowired
    private ZooKeeper zooKeeper;

    /**
     * 分布式排他锁路径
     */
    public static final String lockPath = "/data-cloud-crs/locks/syncmodel";

    @Autowired
    private TaskRecordEntityMapper taskRecordEntityMapper;

    /**
     * 生成分布式任务Id<br/>
     * 成功返回taskId,失败返回null
     *
     * @param taskInfo
     * @return
     */
    public String getTaskId(TaskInfo taskInfo) {
        LocalDateTime localDateTime = LocalDateTime.now();
        //1. 检测时间段
//        if(localDateTime.getHour() != 0){ //属于零时
//            logger.error("生成分布式ID失败，时间不在0-1时内,"+taskInfo);
//            return null;
//        }
        String id = LocalDate.now().toString();

        //2. 查看数据库中是否有该记录任务记录
        TaskRecordEntity oldTask = taskRecordEntityMapper.selectTaskByNoAndType(id, CarModelSyncTaskExecutor.TASK_SYNC_CAR_MODEL);
        if (oldTask != null) {  //任务已经存在
            return null;
        }
        ThreadPoolUtil.submit(this, "clean");
        //3. 在zk中创建
        String value = localDateTime.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME);
        String path = lockPath +"/"+ id;

        try {
            Stat stat = zooKeeper.exists(path, false);
            if (stat == null)
                zooKeeper.create(path, value.getBytes(), ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            else {
                logger.info("生成分布式ID失败，分布式ID已经存在");
                return null;
            }
            return id;
        } catch (KeeperException e) {
            if (e instanceof KeeperException.NodeExistsException) {
                logger.info("生成分布式ID失败，分布式ID已经存在");
            } else {
                logger.error("生成分布式ID失败，", e);
            }
            return null;
        } catch (InterruptedException e) {
            logger.error("生成分布式ID失败，", e);
            return null;
        }
    }

    /**
     * 执行清理zk过期节点操作<br/>
     * 异步线程触发
     */
    public void clean() {
        try {
            List<String> childs = zooKeeper.getChildren(lockPath, true);
            for (String child : childs) {
                byte[] bs = zooKeeper.getData(lockPath + "/" + child, null, null);
                LocalDateTime localDateTime = LocalDateTime.parse(new String(bs), DateTimeFormatter.ISO_LOCAL_DATE_TIME);
                Duration duration = Duration.between(LocalDateTime.now(), localDateTime);
                if (duration.toHours() >= 1) {
                    //间隔超过一小时，即可删除
                    zooKeeper.delete(lockPath +"/"+ child, -1);
                }
            }
        } catch (KeeperException e) {
            logger.error("syncmodel ZooKeeper清理" + lockPath + "路径下过期节点失败", e);
        } catch (InterruptedException e) {
            logger.error("syncmodel ZooKeeper创建" + lockPath + "路径下过期节点失败", e);
        }
    }

    @PostConstruct
    public void initPath() {
        String[] paths = getPaths(lockPath);
        try {
            for (String path : paths) {
                if (StringUtils.isEmpty(path))
                    continue;
                Stat stat1 = zooKeeper.exists(path, false);
                if (stat1 == null)
                    zooKeeper.create(path, null, ZooDefs.Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
            }
        } catch (Exception e) {
            logger.error("ZooKeeper创建" + lockPath + "路径失败", e);
        }
    }

    private static String[] getPaths(String srcPath) {
        String[] strs = srcPath.split("[/]");
        List<String> paths = new ArrayList<>();

        String path = "";
        for (int i = 0; i < strs.length; i++) {
            if (StringUtils.isEmpty(strs[i]))
                continue;
            path += "/" + strs[i];
            paths.add(new String(path));
        }
        String[] array = new String[paths.size()];
        paths.toArray(array);
        return array;
    }
}
